import {CODE_SUCCESS, CODE_UNKNOW, CODE_ISSPAM, CODE_NOEXIST, CODE_INVALIDATE,
  CODE_NOPERMISSION, CODE_NOPERMISSION_OR_NOEXIST, CODE_NETFAILED} from './constants'

function buildUrl(backendUrl, path, params) {
  if (backendUrl[backendUrl.length-1] === '/') {
    backendUrl = backendUrl.substring(0, backendUrl.length-1);
  }
  if (path[0] === '/') {
    path = path.substring(1, path.length);
  }
  let url = backendUrl+'/'+path;
  for (let key in params) {
    url = url.replace('$'+key, params[key]);
  }
  return url;
}

function buildSearch(params) {
  let searchs=[];
  for (let key in params){
    let values = params[key];
    if (typeof(values) !== 'object') {
      values = [values];
    }
    for (let value of values){
      searchs.push(key+'='+value);
    }
  }
  return searchs.join('&');
}

export default class Http{
  
  constructor(backendUrl, codes) {
    this.token;
    this.errorHandlers = {};
    this._backendUrl = backendUrl;
  }
  
  _req(method, path, {data, pathParams={}, ignoreCodes=[], successCodes=[], search={},}) {
    let headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      };
    if (this.token) {
      headers['Authorization'] = this.token;
    }
    let kwargs = {
        method: method,
        headers: headers
      }
    if (data) {
      kwargs.body = JSON.stringify(data);
    }
    let url = buildUrl(this._backendUrl, path, pathParams);
    let searchStr = buildSearch(search);
    if (searchStr){
      url = url+'?'+searchStr;
    }
    return (new Promise((resolve, reject)=>{
      fetch(url, kwargs)
      .then((response)=>response.json())
      .then((responseJson)=>{
        if (responseJson.code == CODE_SUCCESS) {
          resolve(responseJson.data);
        } else {
          this._handleError(responseJson, resolve, reject, ignoreCodes, successCodes);
        }
      })
      .catch((error)=>{
          this._handleError({code: CODE_NETFAILED}, resolve, reject, ignoreCodes, successCodes);
        });
    }));
  }
  
  
  _handleError(responseJson, resolve, reject, ignoreCodes, successCodes) {
    let code = responseJson.code;
    if (successCodes.indexOf(code)>-1){
      resolve();
    } else if (ignoreCodes==='all' || ignoreCodes.includes(code)) {
      reject({code, data:responseJson.data});
    } else {
      if (this.errorHandlers[code]) {
        this.errorHandlers[code](responseJson.errors, responseJson.msg);
      } else if(code === CODE_NETFAILED){
        this.alertMsg('网络出现问题，无法连接到服务器');
      } 
      else if(code === CODE_NOPERMISSION) {
        this.alertMsg('您没有权限执行此操作');
      }
      else if (code === CODE_NOPERMISSION_OR_NOEXIST||code===CODE_NOEXIST) {
        this.alertMsg('您请求的资源不存在');
      }
      else if (code === CODE_ISSPAM) {
        this.alertMsg('您提交的内容含有不正当信息，无法提交');
      } else if (code === CODE_INVALIDATE) {
        this.alertMsg(responseJson.msg||'输入数据错误');
      }
      else{
        this.alertMsg('服务器忙，请稍后再试');
      }
      reject({code, data:responseJson.data});
    }
  }
  
  alertMsg(msg){
    alert(msg)
  }
  
  setToken(token) {
    this.token=token;
  }
  
  setHandler(code, handler) {
    this.errorHandlers[code] = handler;
  }
  
  post(path, data, options={}) {
    let newOptions = Object.assign({data}, options);
    return this._req('POST', path, newOptions);
  }
  
  put(path, data, options={}) {
    let newOptions = Object.assign({data}, options);
    return this._req('PUT', path, newOptions);
  }
  
  del(path, options={}) {
    return this._req('DELETE', path, options);
  }
  
  get(path, options={}) {
    return this._req('GET', path, options)
  }
  
  getImageBase64(url){
    return new Promise((resolve, reject)=>{
      fetch(url, {method: 'GET'}).then((response)=>{
        response.blob().then((blob)=>{
          let reader = new FileReader();
          reader.readAsDataURL(blob); 
          reader.onloadend = function() {
            resolve(reader.result);
          }
        })
      }).catch((error)=>{
        reject(error)
      })
    })
  }
  
  postFile(url, token, key, fileUri, type) {
    let formData = new FormData();
    formData.append('key', key)
    formData.append('token', token)
    formData.append('Content-Type', 'application/octet-stream')
    formData.append('Content-Transfer-Encoding', 'binary')
    let file = {uri: fileUri, name: 'ttt.jpg'};
    if (type){
      file.type = type;
    }
    formData.append('file', file)
    let kwargs = {
        method: 'POST',
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        body: formData
    }
    return (new Promise((resolve, reject)=>{
      fetch(url, kwargs).then((response)=>{
        if (response.ok) {
          resolve()
        } else {
          this._handleError({code: CODE_UNKNOW}, resolve, reject, [], []);
        }
      }).catch((error)=>{
          this._handleError({code: CODE_NETFAILED}, resolve, reject,[],[])
        });
    }));
  }
}
